﻿namespace SimpleWebServices.Data
{
    using System;
    using System.Data;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.IO;
    using System.Text;
    using System.Web.UI;

    public static class DataTableExtensionMethods
    {
        public static string ToCommaSeparatedValues(this DataTable table, bool columnNames)
        {
            string[,] array = table.ToStringArray(columnNames);

            StringBuilder buffer = new StringBuilder();
            for (int y = 0; y < array.GetLength(1); y++)
            {
                for (int x = 0; x < array.GetLength(0); x++)
                {
                    string value = array[x, y];
                    buffer.Append(FormatCommaSeparatedValue(value));
                    buffer.Append(x + 1 == array.GetLength(0) ? Environment.NewLine : ",");
                }
            }

            return buffer.ToString();
        }

        public static string ToFixedWidthValues(this DataTable table, bool columnNames)
        {
            string[,] array = table.ToStringArray(columnNames);
            int[] length = new int[array.GetLength(0)];
            for (int x = 0; x < array.GetLength(0); x++)
            {
                int max = 0;
                for (int y = 0; y < array.GetLength(1); y++)
                {
                    if (!string.IsNullOrEmpty(array[x, y]) && array[x, y].Length > max)
                    {
                        max = array[x, y].Length;
                    }
                }

                length[x] = max;
            }

            StringBuilder buffer = new StringBuilder();
            for (int y = 0; y < array.GetLength(1); y++)
            {
                for (int x = 0; x < array.GetLength(0); x++)
                {
                    string value = array[x, y];
                    buffer.Append(value);
                    if (length[x] > value.Length)
                    {
                        buffer.Append(new string(' ', length[x] - value.Length));
                    }

                    buffer.Append(x + 1 == array.GetLength(0) ? Environment.NewLine : " ");
                }

                if (0 == y)
                {
                    for (int x = 0; x < array.GetLength(0); x++)
                    {
                        buffer.Append(new string('-', length[x]));
                        buffer.Append(x + 1 == array.GetLength(0) ? Environment.NewLine : " ");
                    }
                }
            }

            return buffer.ToString();
        }

        public static string ToHtmlTable(this DataTable table, bool columnNames)
        {
            string[,] array = table.ToStringArray(false);

            StringBuilder buffer = new StringBuilder();
            using (StringWriter writer = new StringWriter(buffer, CultureInfo.InvariantCulture))
            {
                using (HtmlTextWriter html = new HtmlTextWriter(writer, string.Empty))
                {
                    if (0 != table.Columns.Count)
                    {
                        html.RenderBeginTag(HtmlTextWriterTag.Table);
                        if (columnNames)
                        {
                            html.RenderBeginTag(HtmlTextWriterTag.Thead);
                            html.RenderBeginTag(HtmlTextWriterTag.Tr);
                            foreach (DataColumn column in table.Columns)
                            {
                                html.RenderBeginTag(HtmlTextWriterTag.Th);
                                html.WriteEncodedText(column.ColumnName);
                                html.RenderEndTag();
                            }

                            html.RenderEndTag();
                            html.RenderEndTag();
                        }

                        if (0 != table.Rows.Count)
                        {
                            html.RenderBeginTag(HtmlTextWriterTag.Tbody);
                            for (int y = 0; y < array.GetLength(1); y++)
                            {
                                html.RenderBeginTag(HtmlTextWriterTag.Tr);
                                for (int x = 0; x < array.GetLength(0); x++)
                                {
                                    string value = array[x, y];
                                    html.RenderBeginTag(HtmlTextWriterTag.Td);
                                    html.WriteEncodedText(value);
                                    html.RenderEndTag();
                                }

                                html.RenderEndTag();
                            }

                            html.RenderEndTag();
                        }

                        html.RenderEndTag();
                    }
                }
            }

            return buffer.ToString();
        }

        [SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Body", Justification = "There is no need for a jagged array as tables aren't jagged.")]
        [SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Return", Justification = "There is no need for a jagged array as tables aren't jagged.")]
        public static string[,] ToStringArray(this DataTable table, bool columnNames)
        {
            if (null == table)
            {
                throw new ArgumentNullException("table");
            }

            string[,] result = new string[table.Columns.Count, table.Rows.Count + (columnNames ? 1 : 0)];

            int y = 0;
            if (columnNames)
            {
                for (int x = 0; x < table.Columns.Count; x++)
                {
                    result[x, y] = table.Columns[x].ColumnName;
                }

                y++;
            }

            foreach (DataRow row in table.Rows)
            {
                for (int x = 0; x < table.Columns.Count; x++)
                {
                    if (table.Columns[x].DataType.Equals(typeof(DateTime)))
                    {
                        result[x, y] = row.Field<DateTime>(x).ToXmlString();
                    }
                    else
                    {
                        result[x, y] = row[x].ToString();
                    }
                }

                y++;
            }

            return result;
        }

        public static string ToTabSeparatedValues(this DataTable table, bool columnNames)
        {
            string[,] array = table.ToStringArray(columnNames);

            StringBuilder buffer = new StringBuilder();
            for (int y = 0; y < array.GetLength(1); y++)
            {
                for (int x = 0; x < array.GetLength(0); x++)
                {
                    string value = array[x, y];
                    buffer.Append(value.Replace('\t', ' '));
                    buffer.Append(x + 1 == array.GetLength(0) ? Environment.NewLine : "\t");
                }
            }

            return buffer.ToString();
        }

        private static string FormatCommaSeparatedValue(string value)
        {
            string result = null;

            if (string.IsNullOrEmpty(value))
            {
                result = value;
            }
            else
            {
                result = value.Replace("\"", "\"\"");
                if (result.Contains(","))
                {
                    result = string.Concat("\"", result, "\"");
                }
            }

            return result;
        }
    }
}